﻿using System;
using System.CodeDom.Compiler;
using System.Reflection;
using System.Windows.Forms;

namespace ParseExpression
{
    public partial class ExpresssionParser : UserControl
    {
        public ExpresssionParser()
        {
            InitializeComponent();
        }

        public int NumVariables
        {
            get { return oneVariable.Checked ? 1 : 2; }
            
            set
            {
                if ( value == 1)
                {
                    oneVariable.Checked = true;
                }
                else
                {
                    twoVariables.Checked = true;
                }
            }
        }

        public string Expression
        {
            get { return expression.Text; }
            set { expression.Text = value; }
        }

        public ParsedFunction BuildFunc()
        {
            var cdp = CodeDomProvider.CreateProvider("C#");
            var cp = new CompilerParameters { GenerateExecutable = false, GenerateInMemory = true };
            var funcSource = FuncSourceBegin;

            if (oneVariable.Checked)
            {
                funcSource += expression.Text + FuncSourceMiddle + "0" + FuncSourceEnd;
            }
            else
            {
                funcSource += "0" + FuncSourceMiddle + expression.Text + FuncSourceEnd;
            }

            var compiledFunc = cdp.CompileAssemblyFromSource(cp, funcSource);

            if (compiledFunc.Errors.HasErrors)
            {
                MessageBox.Show("wrong expression");
            }
            else
            {
                var assm = compiledFunc.CompiledAssembly;
                var target = assm.GetType("NeverMind");
                if (oneVariable.Checked)
                {
                    const double temp = 0;
                    _lastMethod = target.GetMethod("Func", new[] { temp.GetType() });
                }
                else
                {
                    const double temp = 0;
                    _lastMethod = target.GetMethod("Func", new[] { temp.GetType(), temp.GetType() });
                }
            }

            return new ParsedFunction(Expression, NumVariables, _lastMethod);
        }

        private static string FuncSourceBegin =
            "using System;\n" +
                "class NeverMind {\n" +
                    "public static double Func(double x) {\n" +
                        "double X=x;" + //for morons
                        "return ";

        private static string FuncSourceMiddle =
                        ";\n" +
                    "}" +
                    "public static double Func(double x, double y) {\n" +
                        "double X = x; double Y = y;" + //for morons
                         "return ";

        private static string FuncSourceEnd =
                        ";\n" +
                    "}" +
                    "private static double Sqrt(double d) { return Math.Sqrt(d); }" +
                    "private static double Pow(double d1, double d2) { return Math.Pow(d1,d2); }" +
                "}";

        private MethodInfo _lastMethod;
    }
}
